Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/build: add support for --push #4677

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

danishprakash
Copy link
Contributor

What type of PR is this?

/kind feature

Which issue(s) this PR fixes:

Closes #4671

Special notes for your reviewer:

Extremely WIP draft.

Does this PR introduce a user-facing change?

- add support for `--push` flag to `bud` push image immediately after building

@openshift-ci openshift-ci bot added do-not-merge/work-in-progress kind/feature Categorizes issue or PR as related to a new feature. labels Mar 21, 2023
@rhatdan
Copy link
Member

rhatdan commented Mar 21, 2023

I was thinking this would just be added to the client and not the service side.

buildah build --push

Would internally do

buildah build followed by buildah push.

@rhatdan
Copy link
Member

rhatdan commented Mar 21, 2023

What do you think @nalind @flouthoc @vrothberg

@nalind
Copy link
Member

nalind commented Mar 21, 2023

I was thinking this would just be added to the client and not the service side.

buildah build --push

Would internally do

buildah build followed by buildah push.

That would be simpler; API callers already have a buildah.Push() that they can call directly, and it's less API churn if we add such a call to the tail end of cmd/buildah/buildCmd() if --push.

For the "output=registry" case, setting IsDir in a BuildOutputOption while also adding a Type field that overlaps its meaning is confusing. Making that a special case after we've extracted the output image's rootfs as an archive (an archive which doesn't get used if we're just going to push the image) looks wrong; pushing to a registry probably needs to be an entirely separate branch in generateBuildOutput().

define/build.go Outdated Show resolved Hide resolved
@TomSweeneyRedHat
Copy link
Member

And just in case, we'll need updates to the man page and additional test added for the final PR. From a quick flyby review, it LGTM other than other comments.

@vrothberg
Copy link
Member

What do you think @nalind @flouthoc @vrothberg

I am no fan of mixing multiple commands as it breaks separation of concerns. buildah push has over a dozen command-line options. How would they be exposed in buildah build?

But I leave the decision up to the core maintainers of Buildah.

@rhatdan
Copy link
Member

rhatdan commented Mar 22, 2023

I see this for compatibility with buildx
https://docs.docker.com/engine/reference/commandline/buildx_build/
--push |   | Shorthand for --output=type=registry

I don't think we have to add other options for push, and potentially could have just done this in podman build, but the --output=type calls are handled within buildah.

@flouthoc
Copy link
Collaborator

I concur should we just do this at podman, and only add --output=type=registry to buildah ?

@danishprakash
Copy link
Contributor Author

I was thinking this would just be added to the client and not the service side.

buildah build --push

Would internally do

buildah build followed by buildah push.

I honestly didn't think that is how we'd want to push. On the outset, --push seems like it should be added serially to build but I felt it might not be extensible given there could be modifications/additions to the --output flag in future.

For the "output=registry" case, setting IsDir in a BuildOutputOption while also adding a Type field that overlaps its meaning is confusing. Making that a special case after we've extracted the output image's rootfs as an archive (an archive which doesn't get used if we're just going to push the image) looks wrong; pushing to a registry probably needs to be an entirely separate branch in generateBuildOutput().

You're right, that was an oversight.

@danishprakash
Copy link
Contributor Author

I concur should we just do this at podman, and only add --output=type=registry to buildah ?

So adding the --push flag to podman which would be translated to --output within buildah? Sounds about right to me. That was the original plan as mentioned here.


image := opts.Attrs["name"]
destSpec := opts.Attrs["name"]
dest, err := alltransports.ParseImageName(destSpec)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure this code is correct, or necessary. I know that @mtrmac and @vrothberg frown on parsing specs outside of github.com/containers/image or github.com/containers/common/libimage

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes; as a general principle I think the CLI layer, or something as close to it as possible, should be responsible for turning strings into a unique types.ImageReference.

Admittedly that’s not always possible, but it’s the thing to strive for.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it help if it's moved to util? #4677 (comment)

define/types.go Outdated
@@ -100,6 +100,8 @@ type Secret struct {

// BuildOutputOptions contains the the outcome of parsing the value of a build --output flag
type BuildOutputOption struct {
Type string
Attrs map[string]string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this adding an untyped map instead simple Go fields that exactly represent what we need?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was referenced from buildx but the idea remains the same, for every type, there are (and would be in the future) multiple arguments/options which are consolidated under attributes here. It's possible for us to have individual fields here but those would eventually proliferate into a heterogenous struct type and I'm not sure how ideal that would be.

Copy link
Contributor

@mtrmac mtrmac Apr 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is ultimately up to Buildah maintainers, not me.


IMHO individual fields, or individual types, is much better than Attrs, because Attrs is equally heterogenous, just with much worse compiler / linter support.

We can do interfaces, type checks, wrappers, …

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. Perhaps we can have embedded structs here for individual Types as and when the situation arises? Looking for inputs

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Up to Buildah maintainers.

(My personal style would be:

  • Type field first
  • Then separate sections for individual subtypes, separated by blank lines and with a comment “valid if Type == … ”

so that future maintainers can just look at the type definition and don’t have to chase individual field uses in an IDE.

I agree that separate structs, or even type checks, might be overkill for this small scope.)

define/types.go Outdated Show resolved Hide resolved
define/types.go Outdated Show resolved Hide resolved
pkg/parse/parse.go Outdated Show resolved Hide resolved
pkg/cli/build.go Show resolved Hide resolved
pkg/cli/common.go Show resolved Hide resolved
internal/util/util.go Outdated Show resolved Hide resolved
libimageOptions.Writer = os.Stdout
runtime, err := libimage.RuntimeFromStore(store, &libimage.RuntimeOptions{SystemContext: &types.SystemContext{}})
destString := fmt.Sprintf("%s:%s", dest.Transport().Name(), dest.StringWithinTransport())
_, err = runtime.Push(context.Background(), image, destString, libimageOptions)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Eventually, could libImage have an API that accepts type.ImageReference directly?)

internal/util/util.go Outdated Show resolved Hide resolved
internal/util/util.go Outdated Show resolved Hide resolved
@danishprakash danishprakash force-pushed the bud-push-output branch 4 times, most recently from e22f351 to d6925cd Compare April 25, 2023 06:18
Copy link
Contributor

@mtrmac mtrmac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It’s quite likely I don’t have a full context of the goals / constraints of the Buildx feature set or compatibility; I’m looking basically only at this PR in isolation.

I’ll fully defer to actual Buildah maintainers.

define/types.go Show resolved Hide resolved
internal/util/util.go Outdated Show resolved Hide resolved
internal/util/util.go Outdated Show resolved Hide resolved
pkg/parse/parse.go Outdated Show resolved Hide resolved
define/types.go Outdated Show resolved Hide resolved
define/types.go Show resolved Hide resolved
internal/util/util.go Outdated Show resolved Hide resolved
util/util.go Outdated
@@ -50,6 +51,31 @@ func StringInSlice(s string, slice []string) bool {
return util.StringInSlice(s, slice)
}

func StringToImageReference(image string) (types.ImageReference, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UIArgumentToImageReference? HeuristicUserInputToImageReference? Something along those lines? (Up to Buildah maintainers.)

I, fairly desperately, don’t want this code to be used to “round-trip” between ImageReference and string [there already are other functions for that], and this plain naming of the function suggests that it could be used for that purpose.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I, fairly desperately, don’t want this code to be used to “round-trip” between ImageReference and string

Sorry but would you mind explaining what you mean? Some sort of abuse this function would get by being used in unintended places?

Also, how about ImageStringToImageReference?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some sort of abuse this function would get by being used in unintended places?

Yes. The function is a heuristic that can parse the input using several different format/semantics, depending on what happens to work.

A failure case I’ve seen fairly frequently in this space is finding some pre-existing function like that, similarly targeted at the UI and heuristically doing “what the user meant”, and embedding it somewhere deeper in the call stack, calling it with a string produced from a Go value, without accounting for the details of the heuristics, or possibly the CLI-level heuristics being expanded to add new user-level features. The outcome is that the Go value → string → Go value transformation (which might, sometimes, be unavoidable, e.g. for multi-machine operations) becomes inexact, hard to predict, and possibly even leads to security issues.

Hence all of the concern about not using strings as an internal representation if at all possible, as the easiest preventative measure.

Secondarily, using the right string representation / API. The types.ImageReference values already have an API for producing a string representation, and for creating one from a string representation. That one (alltransports.ParseImageName) should be used anywhere below the CLI heuristic layers, and the new function should be named so that it isn’t accidentally used instead.

So that’s why I would like some mention of UI, and preferably “heuristics” in the name.

“Image string” does not help because it does not disambiguate “a lossy heuristic subject to change” from “a stable round-trip-safe value conversion”, either would apply to images and strings.

internal/util/util.go Show resolved Hide resolved
internal/util/util.go Outdated Show resolved Hide resolved
@StarpTech
Copy link

StarpTech commented May 20, 2023

Hi, I just created containers/podman#18642 It looks related to this PR.

I am no fan of mixing multiple commands as it breaks separation of concerns. buildah push has over a dozen command-line options. How would they be exposed in buildah build?

I agree but a good reason to combine them is to enable parallelism.

@danishprakash danishprakash marked this pull request as ready for review June 8, 2023 11:51
@rhatdan
Copy link
Member

rhatdan commented Jun 27, 2023

@danishprakash Are you still working on this?

@rhatdan
Copy link
Member

rhatdan commented Dec 17, 2023

@danishprakash still working on this?

@github-actions github-actions bot removed the stale-pr label Dec 18, 2023
@danishprakash
Copy link
Contributor Author

Yes, going to get back to this end of this week.

@danishprakash danishprakash force-pushed the bud-push-output branch 3 times, most recently from 0036033 to f9d20a2 Compare January 18, 2024 05:59
@openshift-merge-robot openshift-merge-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Feb 15, 2024
Copy link

Ephemeral COPR build failed. @containers/packit-build please check.

@openshift-merge-robot openshift-merge-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Feb 15, 2024
@jianzhangbjz
Copy link

jianzhangbjz commented May 27, 2024

Any updates? Thanks! And, one more question, for now, once build finished, how can I push all arch images to the registry at once if no --push? Thanks!

Error: unknown flag: --push
See 'podman buildx build --help'

@rhatdan
Copy link
Member

rhatdan commented Jun 3, 2024

@danishprakash would you like me to try to get someone to take this over?

@danishprakash
Copy link
Contributor Author

Tests were pending, I had added them a couple of months back. Two RPM tests are failing, I'm not sure if they're related. Also, this still needs a final pass from @mtrmac.

@rhatdan
Copy link
Member

rhatdan commented Sep 13, 2024

@mtrmac PTAL

@rhatdan
Copy link
Member

rhatdan commented Sep 13, 2024

@nalind @flouthoc PTAL

return fmt.Errorf("failed to export build output: %w", err)
}
}
return nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this right it does no output if not opts.Push?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iiuc, type=image outputs a container image format, only when you specify --output, it additionally pushes the image to the registry.

internal/util/util.go Outdated Show resolved Hide resolved
* pass systemCtx to push util
* fix test

Signed-off-by: Danish Prakash <[email protected]>
@pasquale95
Copy link

Hi, is this still WIP?

@danishprakash
Copy link
Contributor Author

Hi, is this still WIP?

Yes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/feature Categorizes issue or PR as related to a new feature.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Feature]: Add support for "buildx build --push" and/or "buildx build --output=type=registry"